package com.sfac.springCloudAccount.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sfac.account.User;
import com.sfac.account.UserRole;
import com.sfac.account.vo.UserVo;
import com.sfac.common.vo.Result;
import com.sfac.common.vo.Search;
import com.sfac.springCloudAccount.dao.UserDao;
import com.sfac.springCloudAccount.dao.UserRoleDao;
import com.sfac.springCloudAccount.service.TestOpenFeign;
import com.sfac.springCloudAccount.service.UserService;
import com.sfac.springCloudAccount.utils.MD5Util;
import com.sfac.test.City;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.vavr.control.Try;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Optional;

/**
 * UserServiceImpl
 */
@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserDao userDao;
	@Autowired
	private UserRoleDao userRoleDao;
	@Autowired
	private RestTemplate restTemplate;
	@Autowired
	private TestOpenFeign testOpenFeign;

	@Override
	@Transactional
	public Result<User> login(User user) {
		User temp = userDao.getUserByUserNameAndPassword(user.getUserName(), MD5Util.getMD5(user.getPassword()));
		if (temp == null) {
			return new Result<>(Result.ResultStatus.FAILED.code, "用户名或密码错误。");
		}
		return new Result<>(Result.ResultStatus.SUCCESS.code, "Success.", temp);
	}

	@Override
	@Transactional
	public Result<User> insertUser(User user) {
		User temp = userDao.getUserByUserName(user.getUserName());
		if (temp != null) {
			return new Result<>(Result.ResultStatus.FAILED.code, "用户名重复");
		}

		user.setCreateDate(LocalDateTime.now());
		user.setPassword(MD5Util.getMD5(user.getPassword()));
		userDao.insertUser(user);
		if (user.getRoles() != null && user.getRoles().size() > 0) {
			user.getRoles().stream().forEach(item -> {
				userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));
			});
		}

		return new Result<>(Result.ResultStatus.SUCCESS.code, "Insert success.", user);
	}

	@Override
	@Transactional
	public Result<User> updateUser(User user) {
		User temp = userDao.getUserByUserName(user.getUserName());
		if (temp != null && temp.getId() != user.getId()) {
			return new Result<>(Result.ResultStatus.FAILED.code, "用户名重复");
		}

		userDao.updateUser(user);
		userRoleDao.deleteUserRolesByUserId(user.getId());
		if (user.getRoles() != null && user.getRoles().size() > 0) {
			user.getRoles().stream().forEach(item -> {
				userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));
			});
		}

		return new Result<>(Result.ResultStatus.SUCCESS.code, "Update success.", user);
	}

	@Override
	@Transactional
	public Result<Object> deleteUserById(int id) {
		userDao.deleteUserById(id);
		return new Result<>(Result.ResultStatus.SUCCESS.code, "Delete success.");
	}

	@Override
	public User getUserById(int id) {
		return userDao.getUserById(id);
	}

	@Override
	public User getUserByUserName(String userName) {
		return userDao.getUserByUserName(userName);
	}

	@Override
	public PageInfo<User> getUsersBySearch(Search search) {
		search.init();
		PageHelper.startPage(search.getCurrentPage(), search.getPageSize());
		return new PageInfo<>(Optional
				.ofNullable(userDao.getUsersBySearch(search))
				.orElse(Collections.emptyList()));
	}

	@Override
	public void logout() {
	}

	@Override
	public UserVo getUserVoByUserIdAndCityId(int userId, int cityId) {
		User user = userDao.getUserById(userId);
		UserVo userVo = new UserVo();
		BeanUtils.copyProperties(user, userVo);

//		City city = restTemplate.getForObject("http://client-test/api/city/{cityId}", City.class, cityId);
//		userVo.setCity(city);

		/*
		 * - 熔断器策略配置
		 * - 生产者抛出异常或停掉的情况，都会返回默认值
		 */
		CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
				.failureRateThreshold(50)
				.waitDurationInOpenState(Duration.ofMillis(1000))
				.build();
		CircuitBreaker circuitBreaker = CircuitBreaker.of("circuitBreakerPloy", circuitBreakerConfig);
//		Try<City> circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
//				circuitBreaker,
//				() -> restTemplate.getForObject("http://client-test/api/city/{cityId}", City.class, cityId)
//			)).recover(Exception.class, new City());
//		userVo.setCity(circuitBreakerSupplier.get());

		// 断路器加 openFeign 写法
		Try<City> circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
				circuitBreaker,
				() -> testOpenFeign.getCityByCityId(cityId)
		)).recover(Exception.class, new City());
		userVo.setCity(circuitBreakerSupplier.get());

		return userVo;
	}
}
